<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>SoulApp星球</title>
</head>
<body style="text-align:center;">
    <div style="margin:0 auto;">
        <h2>3D Rotate Planet</h2>
        <!-- 设置css宽高设置为canvas宽高的一半，解决绘制模糊问题,效果一般（且会影响canvas绘图时尺寸） -->
        <canvas id="canvas" width="640" height="480" style="border:1px solid #000;">
            您的浏览器不支持HTML5 canvas标签
        </canvas>
    </div>
    <script>
        /**
		 * ----------------------------------------
		 * DOM及参数设置
		 * ----------------------------------------
		 */
        var canv = document.getElementById("canvas");
        var ctx = canv.getContext("2d");
        var width = canv.getAttribute("width");
        var height = canv.getAttribute("height");
        var hWidth = width / 2;
        var hHeight = height / 2;
		ctx.font="20px 微软雅黑";
        
		
		/**
		 * ----------------------------------------
		 * 模型
		 * ----------------------------------------
		 */
		// 星球模型
		class Planet{
			radius = 200;		// 星球半径
			scale = 1.0; 		// 缩放比例
			nodeCount = 128;	// 粒子数
			
			// 构造方法
			constructor(radius,nodeCount){
			this.planetNodeSet = new Set();	// 结点集合
				// 极坐标系，获取分布均匀的点
				for (let i = 1; i < this.nodeCount + 1; i++) {
					// 平均（三维直角得Z轴等分[-1,1]） θ范围[-π/2,π/2])
					let phi = Math.acos(-1.0 + (2.0 * i - 1.0) / this.nodeCount);
					let theta = Math.sqrt(this.nodeCount * Math.PI) * phi;
					// 转空间直角坐标系
					let tx = this.radius * Math.cos(theta) * Math.sin(phi);
					let ty = this.radius * Math.sin(theta) * Math.sin(phi);
					let tz = this.radius * Math.cos(phi);
					// 缩放
					tx = tx * this.scale;
					ty = ty * this.scale;
					tz = tz * this.scale;
					// 加入集合
					this.planetNodeSet.add(new PlanetNode(tx, ty ,tz));
				}
				console.log(this.planetNodeSet)
			}
			// 设置粒子集合
			setPlanetNodeSet(planetNodeSet){
				this.planetNodeSet = planetNodeSet;
			}
		}
		
		// 星球结点模型
		class PlanetNode{
			// 构造函数
			constructor(locX, locY, locZ){
				// 3D坐标
				this.locX = locX;
				this.locY = locY;
				this.locZ = locZ;
				// 2D坐标
				this.loc2DX;
				this.loc2DY;
				// 附加属性
				this.color;		// 颜色
				this.opacity;	// 透明度
				this.label;		// 标志标签
				this.tag;		// 记号标签
				this.size = 2;	// 点半径尺寸
			}
			// 结点一次运动x,y,z各轴的旋转角度
			roteXYZ(mAngleX, mAngleY, mAngleZ){
				// 绕x轴
                var rx1 = this.locX;
                var ry1 = this.locY * Math.cos(mAngleX) - this.locZ * Math.sin(mAngleX);
                var rz1 = this.locY * Math.sin(mAngleX) + this.locZ * Math.cos(mAngleX);
                // 绕y轴
                var rx2 = rx1 * Math.cos(mAngleY) + rz1 * Math.sin(mAngleY);
                var ry2 = ry1;
                var rz2 = - rx1 * Math.sin(mAngleY) + rz1 * Math.sin(mAngleY);
                // 绕z轴
                var rx3 = rx2 * Math.cos(mAngleZ) - ry2 * Math.sin(mAngleZ);
                var ry3 = rx2 * Math.sin(mAngleZ) + ry2 * Math.cos(mAngleZ);
                var rz3 = rz2;
				
				// console.log(rx3,ry3,rz3)
				
				// 更新2d坐标
				this.loc2DX = rx3;
				this.loc2DY = ry3;
			}
			// 绘制方法，压缩Z轴
			draw(){
                ctx.beginPath();
				// 绘制点
                // ctx.arc(hWidth + this.loc2DX, hHeight + this.loc2DY, this.size, 0, 2 * Math.PI);
				// 绘制文字
                ctx.fillText("你好", hWidth + this.loc2DX, hHeight + this.loc2DY);
                ctx.fill();
                ctx.stroke();
			}
		}
		
		// 画2D坐标轴
		function showAxis(){
			ctx.beginPath();
			ctx.moveTo(0, hHeight);
			ctx.lineTo(width,hHeight);
			ctx.moveTo(hWidth, 0);
			ctx.lineTo(hWidth,height);
			ctx.stroke();
		}
		
		// 角度转弧度
		var degToRad = Math.PI / 180;
		function toRad(deg){
			return deg * degToRad;
		}
		
	
		/**
		 * ----------------------------------------
		 * 鼠标/触摸事件
		 * ----------------------------------------
		 */
		
		
		
		/**
		 * ----------------------------------------
		 * 实例化执行
		 * ----------------------------------------
		 */
		var planet = new Planet();
		 // 角度转弧度
		var planetNodeSet = planet.planetNodeSet;
		var fps = 60;	// 帧率,每秒执行fps次
		var mDeg = 0;	// 移动的角度
		var intervalId = setInterval(function(){
			ctx.clearRect(0, 0, width, height); // 清屏
			showAxis();	// 画坐标轴
			for(let node of planetNodeSet){
				node.roteXYZ(toRad(mDeg), toRad(mDeg), 0); // 粒子旋转
				node.draw();	// 画粒子
			}
			mDeg = mDeg + 0.5;	// 每次移动0.5角度
        },1000 / fps);
		 
    </script>
</body>
</html>